#include <string.h>
#include <iostream>

using std::cout;
using std::endl;

//在写时复制中，怎么去实现呢？
//思想就是：浅拷贝 + 引用计数
class String
{
public:
    //每次让指针_pstr指向真正数据的位置
    String()
    /* : _pstr(nullptr) */
    : _pstr(new char[5]() + 4)
    {
        cout << "String()" << endl;
        *(int *)(_pstr - 4) = 1;
    }

    String(const char *pstr)
    : _pstr(new char[strlen(pstr) + 5]() + 4)
    {
        cout << "String(const char *)" << endl;
        strcpy(_pstr, pstr);
        *(int *)(_pstr - 4) = 1;
    }

    //String s2 = s1;
    String(const String &rhs)
    : _pstr(rhs._pstr)//浅拷贝
    {
        cout << "String(const String &)" << endl;
        ++*(int *)(_pstr - 4);
    }

    //s3 = s2
    String &operator=(const String &rhs)
    {
        cout << "String &operator=(const String &)" << endl;
        if(this != &rhs)//1、自复制
        {
            //判断左操作数的引用计数是不是1
            if(--*(int *)(_pstr - 4) == 0)//2、释放左操作数
            {
                delete [] (_pstr - 4);
            }
            
            _pstr = rhs._pstr;//3、浅拷贝
            ++*(int *)(_pstr - 4);
        }
        return *this;//4、返回*this
    }

    //s3[0] = 'H';
    char &operator[](size_t idx)
    {
        if(idx < size())
        {
            //是不是共享
            if(*(int *)(_pstr - 4) > 1)
            {
                char *ptmp = new char[size() + 5]() + 4;
                strcpy(ptmp, _pstr);
                --*(int *)(_pstr - 4);

                _pstr = ptmp;
                *(int *)(_pstr - 4) = 1;
            }
            return _pstr[idx];
        }
        else
        {
            static char nullchar = '\0';
            return nullchar;
        }
    }

    ~String()
    {
        cout << "~String()" << endl;
        if(--*(int *)(_pstr - 4) == 0)
        {
            delete [] (_pstr - 4);
        }
    }

    const char *c_str() const
    {
        return _pstr;
    }

    int getRefCount() const
    {
        return *(int *)(_pstr - 4); 
    }

    size_t size() const
    {
        return strlen(_pstr);
    }

    friend std::ostream &operator<<(std::ostream &os, const String &rhs);
private:
    char *_pstr;
};

std::ostream &operator<<(std::ostream &os, const String &rhs)
{
    if(rhs._pstr)
    {
        os << rhs._pstr;
    }

    return os;
}

void test()
{
    //如果要直接打印引用计数?
    String s1("hello");
    String s2 = s1;
    cout << "s1 = " << s1 << endl;
    cout << "s2 = " << s2 << endl;
    printf("&s1 = %p\n", s1.c_str());
    printf("&s2 = %p\n", s2.c_str());
    cout << "s1.getRefCount() = " << s1.getRefCount() <<endl;
    cout << "s2.getRefCount() = " << s2.getRefCount() <<endl;

    cout << endl;
    String s3("world");
    cout << "s3 = " << s3 << endl;
    printf("&s3 = %p\n", s3.c_str());
    cout << "s3.getRefCount() = " << s3.getRefCount() <<endl;

    cout << endl;
    s3 = s1;
    cout << "s1 = " << s1 << endl;
    cout << "s2 = " << s2 << endl;
    cout << "s3 = " << s3 << endl;
    printf("&s1 = %p\n", s1.c_str());
    printf("&s2 = %p\n", s2.c_str());
    printf("&s3 = %p\n", s3.c_str());
    cout << "s1.getRefCount() = " << s1.getRefCount() <<endl;
    cout << "s2.getRefCount() = " << s2.getRefCount() <<endl;
    cout << "s3.getRefCount() = " << s3.getRefCount() <<endl;

    cout << endl << "对s3[0]执行写操作" <<endl;
    s3[0] = 'H';
    cout << "s1 = " << s1 << endl;
    cout << "s2 = " << s2 << endl;
    cout << "s3 = " << s3 << endl;
    printf("&s1 = %p\n", s1.c_str());
    printf("&s2 = %p\n", s2.c_str());
    printf("&s3 = %p\n", s3.c_str());
    cout << "s1.getRefCount() = " << s1.getRefCount() <<endl;
    cout << "s2.getRefCount() = " << s2.getRefCount() <<endl;
    cout << "s3.getRefCount() = " << s3.getRefCount() <<endl;
}

int main(int argc, char *argv[])
{
    test();
    return 0;
}

